package com.kamistoat.ruoyi.ruoyigateway.service.impl;

import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.kamistoat.ruoyi.ruoyicommoncore.constant.CacheConstants;
import com.kamistoat.ruoyi.ruoyicommoncore.constant.Constants;
import com.kamistoat.ruoyi.ruoyicommoncore.exception.CaptchaException;
import com.kamistoat.ruoyi.ruoyicommoncore.utils.StringUtils;
import com.kamistoat.ruoyi.ruoyicommoncore.utils.uuid.IdUtils;
import com.kamistoat.ruoyi.ruoyicommoncore.web.domain.AjaxResult;
import com.kamistoat.ruoyi.ruoyicommonredis.utils.RedisUtils;
import com.kamistoat.ruoyi.ruoyicommonredis.utils.RedissonUtils;
import com.kamistoat.ruoyi.ruoyigateway.config.properties.CaptchaProperties;
import com.kamistoat.ruoyi.ruoyigateway.service.ValidateCodeService;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
public class ValidateCodeServiceImpl implements ValidateCodeService {

    // 原项目这里直接使用 @Resource(name = "captchaProducer") 代替下面的两个@。不过@Resource并不是spring提供的注解而是javax，还是推荐使用@Autowired
    // 由于两个都是 DefaultKaptcha 类型，所以必须显式指定 Bean的名字
    @Autowired
    @Qualifier(value = "captchaProducer")
    Producer captchaProducer;

    @Autowired
    @Qualifier(value = "captchaProducerMath")
    Producer captchaProducerMath;

    @Autowired
    RedissonUtils redissonUtils;

    @Autowired
    CaptchaProperties captchaProperties;


    /**
     * 生成验证码
     *
     * @return 前后端响应体
     * @throws IOException
     * @throws CaptchaException
     */
    @Override
    public AjaxResult createCaptcha() throws IOException, CaptchaException {
        AjaxResult ajaxResult = AjaxResult.success();
        Boolean captchaEnabled = captchaProperties.getEnabled();
        ajaxResult.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled) {
            return ajaxResult;
        }

        // 生成验证码缓存标识
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;

        String capStr = null;
        String capCode = null;
        // BufferedImage--在内存中为图片开辟缓存空间
        BufferedImage bufferedImage = null;

        // 生成验证码
        String captchaType = captchaProperties.getType();
        if (captchaType.equals("math")) {
            // 获取的字符串为 3+2=?@5
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));  // 3+2=?
            capCode = capText.substring(capText.lastIndexOf("@") + 1);  // 5
            bufferedImage = captchaProducerMath.createImage(capStr);
        } else if (captchaType.equals("char")) {
            capStr = captchaProducer.createText();
            capCode = capStr;
            bufferedImage = captchaProducer.createImage(capStr);
        }

        // 入缓存. 过期时间为2分钟
        redissonUtils.setCacheObject(verifyKey, capCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);

        // 将图片转换为 OutputStream
        // FastByteArrayOutputStream 继承 OutputStream，性能更高
        FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream();
        try {
            // ImageIO.write(图片来源，输出格式，图片输出源)
            ImageIO.write(bufferedImage, "jpg", outputStream);
        } catch (IOException ioException) {
            return AjaxResult.error(ioException.getMessage());
        }

        ajaxResult.put("uuid", uuid);
        ajaxResult.put("img", Base64.encode(outputStream.toByteArray()));  // 以Base64字符串返回
        return ajaxResult;
    }

    /**
     * 校验验证码
     *
     * @param code 前端输入的验证码
     * @param uuid redis缓存标识
     * @throws CaptchaException
     */
    @Override
    public void checkCaptcha(String code, String uuid) throws CaptchaException {
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String exceptionMessage = "";

        if (StringUtils.isEmpty(code)) {
            exceptionMessage = "验证码不能为空";
        } else if (StringUtils.isEmpty(uuid)) {
            exceptionMessage = "验证码已失效";
        } else {
            String capCode = (String) redissonUtils.getCacheObject(verifyKey);
            if (StringUtils.isEmpty(capCode)) {
                exceptionMessage = "验证码已失效";
            } else if (!capCode.equalsIgnoreCase(code)) {
                exceptionMessage = "验证码错误";
            }
        }
        redissonUtils.deleteObject(verifyKey);
        if (!exceptionMessage.equals("")) {
            throw new CaptchaException(exceptionMessage);
        }
    }
}
